﻿package fwk.utiles.infobulle
{

	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.InteractiveObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.text.TextField;
	

	
	/**
	 * To display a bubble info when rollOver a clip (target)
	 */
	public class InfoBulle extends MovieClip implements IInfoBulle {
		
		private var _mcInfobulle:MovieClip;
		private var _clip:MovieClip;
		private var _textField:TextField;
		
		private var _targetClip:DisplayObject;
		private var _margeX:Number;
		private var _margeY:Number;
		private var _position:String;
		private var _margeXtexte:Number;
		private var _centerFleche:Boolean = true;
		private var _margeYtexte:Number;
		
		private var _type:String = InfoBulleAlign.TYPE_MOUSEMOVE;
		private var _delayMouseMove:int = 4;
		private var _mouseOverEnabled:Boolean = true;
		private var _stage:Stage;
		

		

		/**
		 * Create an instance of InfoBulle (bubble info)
		 * @param mc The clip contains the assets of the infobulle
		 */
		public function InfoBulle(mc:MovieClip = null)
		{
			
			if( mc != null){
				_mcInfobulle = mc;
				addChild(_mcInfobulle);
			}else{
				_mcInfobulle = this;
			}
			_clip = _mcInfobulle.getChildByName("clip") as MovieClip;
			_textField = _clip.texte.tTexte as TextField;
			
			_margeX		= 0;
			_margeY		= 0;
			_position	= InfoBulleAlign.BOTTOM;
			_margeXtexte = _clip.texte.x - _clip.fond.x;
			_margeYtexte = _clip.texte.y - _clip.fond.y;
			
			
			_mcInfobulle.addEventListener("onHideComplete", onHideComplete);
			
			mouseEnabled = false;
			mouseChildren = false;
			
			_mcInfobulle.mouseEnabled = false;
			_mcInfobulle.mouseChildren = false;
			
			
		}
		/**
		 * Initialize the bubble info. The size is automatically calculated from the size of textField (with the text)
		 */
		public function init()
		{
			
			//taille
			_clip.fond.tm.width = (_margeXtexte * 2 + _clip.texte.width) - (_clip.fond.tl.width + _clip.fond.tr.width);
			_clip.fond.bm.width = _clip.fond.tm.width;
			_clip.fond.m.width  = _clip.fond.tm.width + _clip.fond.tl.width + _clip.fond.tr.width;
			_clip.fond.tr.x = _clip.fond.tm.x + _clip.fond.tm.width;
			_clip.fond.br.x = _clip.fond.tr.x;
			
			var calcHeight:Number = (_margeYtexte * 2 + _clip.texte.height) - (_clip.fond.tl.height + _clip.fond.bl.height);
			
			if (calcHeight > 0) {
				_clip.fond.m.height = calcHeight;
			} else {
				_clip.fond.m.height = 0;
			}
			
			_clip.fond.bm.y = _clip.fond.m.y + _clip.fond.m.height;
			_clip.fond.bl.y = _clip.fond.bm.y;
			_clip.fond.br.y = _clip.fond.bm.y;
			
			// position
			if(_centerFleche) {
				_clip.fond.x 		= - _clip.fond.width / 2;
				_clip.fleche.x  	= 0;
				_clip.texte.x 		= - _clip.fond.width / 2 + _margeXtexte;
			}
			if (_position == InfoBulleAlign.BOTTOM)
			{
				_clip.fond.y = _clip.fleche.y + _clip.fleche.height;
				
			}else if (_position == InfoBulleAlign.TOP)
			{
				_clip.fleche.scaleY = -1;
				_clip.fond.y = _clip.fleche.y - _clip.fleche.height - _clip.fond.height;
			}
			_clip.texte.y 		=  _clip.fond.y + _margeYtexte;
			
			/*this.x = _targetClip.x + _targetClip.width / 2;
			if (_position == InfoBulle.BOTTOM) this.y = _targetClip.y + _targetClip.height + _marge;
			else if (_position == InfoBulle.TOP) this.y = _targetClip.y  - _marge;*/

	

		}
		/**
		 * Remove and clear internal properties
		 */
		public function dispose():void
		{
			try {
				_targetClip.stage.removeChild(this);
			}catch(e) {

			}
			try {
				_targetClip.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOverClip);
				_targetClip.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOutClip);
			}catch (e) {
				
			}
			
			try {
				_targetClip.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveTargetClip);
			}catch (e) {
				
			}
			
			try {
				_mcInfobulle.removeEventListener("onHideComplete", onHideComplete);
			}catch (e) {
				
			}
			
			try {
				_mcInfobulle.removeEventListener("onHideComplete", onHideCompleteMouseOut);
			}catch (e) {
				
			}
			
			try {
				_stage.removeEventListener(Event.ENTER_FRAME, onMouseMoveTargetClip);
			}catch (e) {
				
			}
			
			_targetClip = null;
			_stage = null;
		}
		
		private function onMouseOutClip(e:MouseEvent):void 
		{
			_mcInfobulle.addEventListener("onHideComplete", onHideCompleteMouseOut);
			hide();
		}
		
		private function onHideCompleteMouseOut(e:Event):void 
		{
			if (_type == InfoBulleAlign.TYPE_MOUSEMOVE) {
				_targetClip.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveTargetClip);
			}
			_mcInfobulle.removeEventListener("onHideComplete", onHideCompleteMouseOut);
		}
		
		private function onMouseOverClip(e:MouseEvent):void 
		{
			
			display();
			
			if (_type == InfoBulleAlign.TYPE_MOUSEMOVE) {
				_mcInfobulle.x = _targetClip.stage.mouseX + _margeX;
				_mcInfobulle.y = _targetClip.stage.mouseY + _margeY;
				_stage.addEventListener(Event.ENTER_FRAME, onMouseMoveTargetClip);
			}else {
				var tempX:Number;
				tempX = _targetClip.x;

				var tempY:Number;
				if (_position == InfoBulleAlign.BOTTOM) tempY = _targetClip.y + _targetClip.height + _margeY;
				else if (_position == InfoBulleAlign.TOP) tempY = _targetClip.y  - _margeY;
				
				
				var bullePoint:Point = new Point(tempX + _margeX, tempY);
				var newPoint:Point = _targetClip.parent.localToGlobal(bullePoint);
				if (_centerFleche) {
					_mcInfobulle.x = newPoint.x;
					_mcInfobulle.y = newPoint.y;
				}else {
					_mcInfobulle.x = newPoint.x - _clip.fleche.x;
					_mcInfobulle.y = newPoint.y - _clip.fleche.y;
				}

			}
		}
		
		
		
		
		/**
		 * To display the bubble info
		 * @param xInfobulle the position x of the bubble info (relative to stage)
		 * @param yInfobulle the position y of the bubble info (relative to stage)
		 */
		public function display(xInfobulle:Number = NaN, yInfobulle:Number = NaN):void
		{
			//trace("display");
			//trace("content bubble : " + _clip.texte.tTexte.text);
			
			init();
			
			_stage = _targetClip.stage;
			
			_mcInfobulle.gotoAndPlay("display");
			_targetClip.stage.addChild(this);
			
			if ( !isNaN(xInfobulle) && !isNaN(yInfobulle)) {
				_mcInfobulle.x = xInfobulle;
				_mcInfobulle.y = yInfobulle;
			}
			

		}
		/**
		 * To hide the bubble info
		 */
		public function hide():void
		{
			//trace("hide");
			_mcInfobulle.gotoAndPlay("hide");
		}
		private function onHideComplete(evt:Event)
		{
			//trace("onHideComplete");

			if ( _mcInfobulle.parent != null) {
				_stage.removeEventListener(Event.ENTER_FRAME, onMouseMoveTargetClip);
				_stage.removeChild(this);
			}

			
		}
		

		private function onMouseMoveTargetClip(e:Event):void 
		{
			
			//trace("onMouseMoveTargetClip")
			
			if (_targetClip.parent != null && _targetClip.stage != null) {
				
				var dx:Number = _targetClip.stage.mouseX - _mcInfobulle.x + _margeX;
				var dy:Number = _targetClip.stage.mouseY - _mcInfobulle.y + _margeY;
				
				_mcInfobulle.x += int(dx/ _delayMouseMove);
				_mcInfobulle.y += int(dy/ _delayMouseMove);

			}

			
		
		}
		
		
		/**
		 * Return the Clip contains the textField (named tTexte) of the bubble info
		 */
		public function get texteClip():MovieClip
		{
			return _clip.texte;
			
		}
		/**
		 * The target clip of the bubble info. Need to set before call the init method.
		 * @param val The target clip of the bubble info
		 */
		public function set target(val:DisplayObject)
		{
			if (_targetClip != null)
			{
				if(_mouseOverEnabled){
					_targetClip.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOverClip);
					_targetClip.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOutClip);
				}
			}
			
			_targetClip = val;
			if ( _targetClip is Sprite) {
				(_targetClip as Sprite).buttonMode = true;
			}
			
			
			_mouseOverEnabled = true;
			_targetClip.addEventListener(MouseEvent.MOUSE_OVER, onMouseOverClip);
			_targetClip.addEventListener(MouseEvent.MOUSE_OUT, onMouseOutClip);
			
			
		}
		/**
		 * The position type relative to the target clip (or to the mouse position if the type is InfoBulle.TYPE_MOUSEMOVE). Need to set before call the init method.
		 * @param val The position type relative to the target clip. The valid value are InfoBulle.BOTTOM, InfoBulle.TOP
		 */
		public function set position(val:String)
		{
			_position = val;
			
		}
		/**
		 * Indicate if the arrow picto of the bubble info is center. Need to set before call the init method.
		 * @param val true or false
		 */
		public function set centerFleche(val:Boolean)
		{
			_centerFleche = val;
			
		}
		/**
		 * Indicate if the arrow picto bubble info is center. Need to set before call the init method.
		 * @return true or false
		 */
		public function get centerFleche():Boolean
		{
			return _centerFleche;
			
		}
		/**
		 * The distance x,y between the bubble info and his target (or of the mouse position if the type is InfoBulle.TYPE_MOUSEMOVE)
		 * @param val A value in pixel
		 */
		public function set marge(val:Number)
		{
			_margeX = val;
			_margeY = val;
			
		}
		/**
		 * The distance x between the bubble info and his target (or of the mouse position if the type is InfoBulle.TYPE_MOUSEMOVE)
		 * @param val A value in pixel
		 */
		public function set margeX(val:Number)
		{
			_margeX = val;
			
		}
		/**
		 * The distance y between the bubble info and his target (or of the mouse position if the type is InfoBulle.TYPE_MOUSEMOVE)
		 * @param val A value in pixel
		 */
		public function set margeY(val:Number)
		{
			_margeY = val;
			
		}
		/**
		 * The delay value of the bubble info movement (if the type is InfoBulle.TYPE_MOUSEMOVE)
		 * @return A number. Default 4
		 */
		public function get delayMouseMove():int { return _delayMouseMove; }
		
		/**
		 * The delay value of the bubble info movement (if the type is InfoBulle.TYPE_MOUSEMOVE)
		 * @param value A number. Default 4
		 */
		public function set delayMouseMove(value:int):void 
		{
			_delayMouseMove = value;
		}
		
		/**
		 * Enable or disable the listeners MouseOver on the target of the bubble info. Default true
		 * @return true or false, Default true
		 */
		public function get mouseOverEnabled():Boolean { return _mouseOverEnabled; }
		
		/**
		 * Enable or disable the listeners MouseOver on the target of the bubble info. Default true
		 * @return value true or false. Default true
		 */
		public function set mouseOverEnabled(value:Boolean):void 
		{
			if ( _mouseOverEnabled != value) {
				
				if (value && !_mouseOverEnabled) {
					_targetClip.addEventListener(MouseEvent.MOUSE_OVER, onMouseOverClip);
					_targetClip.addEventListener(MouseEvent.MOUSE_OUT, onMouseOutClip);
				}else if(!value && _mouseOverEnabled){
					_targetClip.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOverClip);
					_targetClip.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOutClip);
				}
				
				_mouseOverEnabled = value;
			}
		}
		
		/**
		 * The type of the bubble info. The valid type are InfoBulle.TYPE_MOUSEMOVE and InfoBulle.TYPE_STATIC
		 * @return The type of the bubble info
		 */
		public function get type() : String {
			return _type;
		}
		
		/**
		 * The type of the bubble info. 
		 * @param type The valid type are InfoBulle.TYPE_MOUSEMOVE (the infobulle follow the mouse) and InfoBulle.TYPE_STATIC (the bubble info don't move)
		 */
		public function set type(type : String) : void {
			_type = type;
		}
		
		public function get textField():TextField { return _textField; }

		public function set textField(value:TextField):void 
		{
			texteClip.removeChild(_textField);
			_textField = value;
			texteClip.addChild(_textField);
		}
		

	}

}